# -*-coding:utf-8-*-
from queue import Queue, Empty
from threading import Thread, local
import time
from concurrent.futures import ThreadPoolExecutor, Future, as_completed

# ----------------------线程----------------------
def product(name, r, q):
    while True:
        try:
            x = r.get_nowait()
        except Empty:
            break
        q.put(x)
        print(name + '-生产-' + str(x) + '\n', end='')
        time.sleep(0.5)


def consumer(name, q):
    while True:
        try:
            x = q.get(timeout=3)
        except Empty:
            break
        print(name + '-消费-' + str(x) + '\n', end='')
        time.sleep(0.5)


def main():
    r = Queue(10)
    for i in range(10):
        r.put(i)
    q = Queue(10)
    t1 = Thread(target=product, args=('生产者1', r, q))
    t2 = Thread(target=product, args=('生产者2', r, q))
    t3 = Thread(target=consumer, args=('消费者1', q))
    t4 = Thread(target=consumer, args=('消费者2', q))
    ts = [t1, t2, t3, t4]
    for t in ts:
        t.start()
    for t in ts:
        t.join()
    print('完成')


# ----------------------线程池----------------------
"""
1.Future提供了如下方法:
    (1)cancel()：取消该Future表示的线程任务。如果该任务正在执行则不可取消，返回False，否则程序会取消该任务，并返回True
    (2)cancelled()：返回Future表示的线程任务是否被成功取消
    (3)running()：如果Future表示的线程任务正在执行返回True
    (4)done()：如果该Future表示的线程任务被成功取消或执行，则返回True
    (5)result(timeout=None)：获取该Future表示的线程任务最后返回的结果 如果线程任务未完成，该方法将会阻塞当前线程，timeout指定最多阻塞多少秒
    (6)add_done_callback(fn）：为该Future表示的线程任务注册回调函数，当该任务成功完成时，程序会自动触发该函数,fn的参数为Future

2.在用完线程池后，应该调用该线程池的shutdown方法，调用shutdown方法后的线程池不再接收新任务，但会将以前所有的己提交任务执行完成
"""
def work_executor(i):
    print('运行线程' + str(i) + '\n', end='')
    time.sleep(1)
    return i

def main3():
    with ThreadPoolExecutor(4) as exexcutor:
        # 通过submit逐个提交线程
        futures = [exexcutor.submit(work_executor, i) for i in range(4)]
        # as_completed能按照线程的完成顺序返回，比直接调用future.result()更好
        for f in as_completed(futures):
            print(f.result())

        # 通过map批量提交线程,返回的是结果迭代器
        results = exexcutor.map(work_executor, [4, 5, 6])
        print(list(results))

    print('主线程结束')


# ----------------------threadlocal----------------------
"""
ThreadLocal变量虽然是全局变量，但每个线程都只能读写自己线程的独立副本，互不干扰。
ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题。
"""
local_list = local()

def work():
    local_list.list = []
    for i in range(10):
        local_list.list.append(i)
        time.sleep(0.1)
    print(local_list.list)

def main2():
    ts = [Thread(target=work) for _ in range(2)]
    for t in ts:
        t.start()
    for t in ts:
        t.join()
    print('完成')


if __name__ == '__main__':
    # main()
    # main2()
    main3()
